package com.js.data.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.js.data.common.constant.SymbolConstant;
import com.js.data.common.dto.UserMenuVO;
import com.js.data.common.exception.ApiException;
import com.js.data.common.utils.StringUtils;
import com.js.data.common.dto.SecurityUserDTO;
import com.js.data.system.dto.BatchRolePermDTO;
import com.js.data.system.dto.RoleDTO;
import com.js.data.system.dto.RoleUserDTO;
import com.js.data.system.entity.SysMenu;
import com.js.data.system.entity.SysRole;
import com.js.data.system.entity.SysUserRole;
import com.js.data.system.mapper.SysMenuMapper;
import com.js.data.system.mapper.SysRoleMapper;
import com.js.data.system.query.RoleQuery;
import com.js.data.system.service.RoleMenuService;
import com.js.data.system.service.RoleService;
import com.js.data.system.service.UserRoleService;
import com.js.data.system.vo.RolePageVO;
import com.js.data.system.vo.SimpleRoleVO;
import com.js.data.system.vo.SimpleUserVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author wujj
 * @since 2022-09-06
 */
@Service
public class RoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements RoleService {


    @Resource
    private RoleMenuService roleMenuService;

    @Resource
    private UserRoleService userRoleService;

    @Resource
    private SysMenuMapper sysMenuMapper;

    /**
     * 角色分页
     *
     * @param query 查询条件
     * @return IPage<RolePageVO>
     */
    @Override
    public IPage<RolePageVO> pageRole(RoleQuery query) {
        Page<RolePageVO> page = new Page<>(query.getCurrent(), query.getSize());
        return getBaseMapper().selectPageVO(page, query);
    }

    /**
     * 新增角色
     *
     * @param roleDTO 角色表单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRole(RoleDTO roleDTO) {
        if (lambdaQuery().eq(SysRole::getRoleName, roleDTO.getRoleName()).one() != null) {
            throw new ApiException("角色名已存在");
        }
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(roleDTO, sysRole);
        save(sysRole);
//        roleDeptService.saveBatchToDB(roleDTO.getDeptIds(), sysRole.getId());
    }

    /**
     * 修改角色
     *
     * @param id      角色id
     * @param roleDTO 角色表单
     */
    @Override
    public void editRole(Long id, RoleDTO roleDTO) {
        SysRole sysRoleEX = getById(id);
        Optional.ofNullable(sysRoleEX).orElseThrow(() -> new ApiException("角色不存在"));
        if (lambdaQuery().eq(SysRole::getRoleName, roleDTO.getRoleName()).ne(SysRole::getId, id).one() != null) {
            throw new ApiException("角色名已存在");
        }
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(roleDTO, sysRole);
        sysRole.setId(id);
        updateById(sysRole);
    }

    /**
     * 删除角色
     *
     * @param id 角色id
     */
    @Override
    public void deleteRole(Long id) {
        // 角色下是否有用户
        if (userRoleService.listSimpleUserByRoleId(id).size() > 0) {
            throw new ApiException("角色下存在用户,不能删除");
        }
        removeById(id);
        roleMenuService.removeByRoleId(id);
    }

    /**
     * 启用角色
     *
     * @param id 角色id
     */
    @Override
    public void stateRole(Long id) {
        SysRole sysRoleEX = getById(id);
        Optional.ofNullable(sysRoleEX).orElseThrow(() -> new ApiException("角色不存在"));
        String oldState = sysRoleEX.getState();
        if (SymbolConstant.ZERO_STR.equals(oldState)) {
            sysRoleEX.setState(SymbolConstant.ONE_STR);
        }
        if (SymbolConstant.ONE_STR.equals(oldState)) {
            sysRoleEX.setState(SymbolConstant.ZERO_STR);
        }
        updateById(sysRoleEX);
    }

    /**
     * 返回简单角色信息
     *
     * @param roleName 角色名称
     * @return List<SimpleRoleVO>
     */
    @Override
    public List<SimpleRoleVO> listSimpleRole(String roleName) {
        LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNoneBlank(roleName)) {
            queryWrapper.like(SysRole::getRoleName, roleName);
        }
        List<SimpleRoleVO> retList = new ArrayList<>();
        list(queryWrapper).forEach(data -> {
            SimpleRoleVO simpleRoleVO = new SimpleRoleVO();
            simpleRoleVO.setRoleId(data.getId());
            simpleRoleVO.setRoleName(data.getRoleName());
            retList.add(simpleRoleVO);
        });

        return retList;
    }

    /**
     * 根据角色查找关联用户列表
     *
     * @param id 角色id
     * @return List<SimpleUserVO>
     */
    @Override
    public List<SimpleUserVO> listSimpleUserByRoleId(Long id) {
        return userRoleService.listSimpleUserByRoleId(id);
    }

    /**
     * 角色下人员
     *
     * @param roleUserDTO 角色下用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRoleUser(RoleUserDTO roleUserDTO) {
        Long roleId = roleUserDTO.getRoleId();
        userRoleService.removeByRoleId(roleUserDTO.getRoleId());
        List<SysUserRole> userRoles = new ArrayList<>();
        roleUserDTO.getUserIds().forEach(userId -> {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setRoleId(roleId);
            sysUserRole.setUserId(userId);
            userRoles.add(sysUserRole);
        });
        userRoleService.saveBatch(userRoles);
    }

    /**
     * 角色功能权限列表
     *
     * @param roleId 角色id
     * @return List<RoleMenuPermDTO>
     */
    @Override
    public List<Long> listRoleMenuPerm(Long roleId) {
        return roleMenuService.listMenuIdByRoleId(roleId);
    }

    /**
     * 角色菜单
     *
     * @param batchRolePermFrom 提交表单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void roleMenuPerm(BatchRolePermDTO batchRolePermFrom) {
        Long roleId = batchRolePermFrom.getId();
        SysRole sysRoleEX = getById(roleId);
        Optional.ofNullable(sysRoleEX).orElseThrow(() -> new ApiException("角色不存在"));
        roleMenuService.removeByRoleId(roleId);
        List<Long> menuIdList = batchRolePermFrom.getMenuIds();
        if (CollectionUtil.isNotEmpty(menuIdList)) {
            roleMenuService.saveBatchToDB(roleId, menuIdList);
        }
    }

    /**
     * 获取用户菜单权限
     *
     * @param user 用户
     * @return List<GrantedAuthority>
     */
    @Override
    public List<GrantedAuthority> getGrantedAuthorities(SecurityUserDTO user) {
        Set<String> permissions = new HashSet<>();
        Set<Long> roles = userRoleService.listUserRoleIds(user.getId());
        if (CollectionUtil.isEmpty(roles)) {
            return permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
        }
        List<SysMenu> menus = roleMenuService.listMenuIdByRoleIds(roles, 1);
        if (CollectionUtil.isEmpty(menus)) {
            return permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
        }
        Set<UserMenuVO> retList = new HashSet<>();
        Set<Integer> parentMenuIds = new HashSet<>();
        menus.forEach(data -> {
            String parentIds = data.getParentIds();
            UserMenuVO userMenuVO = new UserMenuVO();
            BeanUtils.copyProperties(data, userMenuVO);
            retList.add(userMenuVO);
            for (String id : parentIds.split(SymbolConstant.COMMA)) {
                parentMenuIds.add(Integer.valueOf(id));
            }
            if (StringUtils.isNoneBlank(data.getPerm())) {
                permissions.add(data.getPerm());
            }
        });
        if (CollectionUtil.isNotEmpty(parentMenuIds)) {
            LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(SysMenu::getId, parentMenuIds).eq(SysMenu::getState, 1);
            sysMenuMapper.selectList(queryWrapper).forEach(menu -> {
                UserMenuVO userMenuVO = new UserMenuVO();
                BeanUtils.copyProperties(menu, userMenuVO);
                retList.add(userMenuVO);
                if (StringUtils.isNoneBlank(menu.getPerm())) {
                    permissions.add(menu.getPerm());
                }
            });
        }
        user.setUserMenu(retList);
        return permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
    }
}
